#pragma once

#include <vex/functional/make_raw_multicast_delegate.h>
#include <vex/functional/implementation/invokable_event_default_impl.h>

namespace vex { namespace functional {
    /// <summary>
    /// Create an empty invokable event with default "void" reducer. 
    /// Applies only if <c>TSignature</c> has <c>void</c> return type
    /// </summary>
    template<class TSignature> auto make_raw_invokable_event()
        -> typename implementation::invokable_event_default_impl<TSignature>*
    {
        return core::make_raw_handle< 
            implementation::invokable_event_default_impl<TSignature>
        >();
    }

    /// <summary>
    /// Create an empty invokable event with default "non-void" reducer. You must use the
    /// vex::functional::default_reducer helper function to pass a suitable default value which
    /// will be returned whenever an empty event is invoked
    /// </summary>
    template< class TSignature, class TDefault > auto make_raw_invokable_event(
        implementation::default_value_reducer<TDefault> p_default)
        -> typename implementation::invokable_event_default_impl<
            TSignature,
            implementation::default_value_reducer<TDefault>
        >*
    {
        return core::make_raw_handle< 
            implementation::invokable_event_default_impl<
                TSignature, 
                implementation::default_value_reducer<TDefault>
            >
        >(std::move(p_default));
    }

    /// <summary>
    /// Create an empty invokable event with custom reducer. A valid reducer is a callable type
    /// which satisfies the <c>Reducer</c> concept. The created invokable event has a return type identical
    /// with the return type of the reducer. The reducer must define an <c>operator()(invoker_range<T>*)</c> 
    /// where <c>T</c> is implicitely convertible from result type of <c>TSignature</c>
    /// </summary>
    template<class TSignature, class TReducer> auto make_raw_invokable_event(
        TReducer&& p_reducer)
        -> typename implementation::invokable_event_default_impl<
            TSignature,
            typename std::remove_reference<TReducer>::type
        >*
    {
        BOOST_CONCEPT_ASSERT((concept::Reducer<TReducer, TSignature>));
        return core::make_raw_handle< 
            implementation::invokable_event_default_impl<
                TSignature, 
                typename std::remove_reference<TReducer>::type
            >
        >(std::forward<TReducer>(p_reducer));
    }
}}